/**
 * Created by GanJc on 2015/9/9.
 */

console.log("这个文件展示js的面向对象");

var Student={
    name : "姓名",
    age:18,
    run:function(){
        console.log(this.name+"正在跑步!");
    }
};

var xiaoming = {
    name:"小明",
    age:"19"
};
xiaoming.__proto__ = Student;
xiaoming.run();
console.log(xiaoming);

//请注意，上述代码仅用于演示目的。在编写JavaScript代码时，不要直接用obj.__proto__去改变一个对象的原型，
//并且，低版本的IE也无法使用__proto__。Object.create()方法可以传入一个原型对象，
//并创建一个基于该原型的新对象，但是新对象什么属性都没有，因此，我们可以编写一个函数来创建xiaoming：
function createStudent(name) {
    // 基于Student原型创建一个新对象:
    var s = Object.create(Student);
    // 初始化新对象:
    s.name = name;
    return s;
}

var xiaohong = createStudent("小苹果");
xiaohong.run();


//构造函数
//除了直接用{ ... }创建一个对象外，JavaScript还可以用一种构造函数的方法来创建对象。它的用法是，先定义一个构造函数：

function People(name) {
    this.name = name;
    this.hello = function () {
        console.log('Hello, ' + this.name + '!');
    }
}
//你会问，咦，这不是一个普通函数吗？
//这确实是一个普通函数，但是在JavaScript中，可以用关键字new来调用这个函数，并返回一个对象：
var xiaodong  = new People("小冬瓜");
xiaodong.hello();
console.log(xiaodong.constructor === People.prototype.constructor);
console.log(xiaodong.constructor === People);
console.log(People === People.prototype.constructor);

//共享函数  节省内存
var xiaoxi = new People("小西瓜");
xiaoxi.hello();
console.log(xiaodong.hello);
console.log(xiaoxi.hello);
console.log(xiaodong.hello===xiaoxi.hello);


//要让创建的对象共享一个hello函数，根据对象的属性查找原则，
//我们只要把hello函数移动到xiaoming、xiaohong这些对象共同的原型上就可以了，也就是Student.prototype：

function People2(name) {
    this.name = name;
}
People2.prototype.hello = function () {
    console.log('Hello2, ' + this.name + '!');
};
var xiaoyun = new People2("小云");
var xiaoyu = new People2("小雨");
console.log(xiaoyun.hello);
console.log(xiaoyu.hello);
console.log(xiaoyun.hello===xiaoyu.hello);


//最后，我们还可以编写一个createStudent()函数，在内部封装所有的new操作。一个常用的编程模式像这样：

function Student3(props) {
    this.name = props.name || '匿名'; // 默认值为'匿名'
    this.grade = props.grade || 1; // 默认值为1
    this.hey = function () {
        console.log("hiiiiiiiiiii");
    }
}

Student3.prototype.hello = function () {
    console.log('Hello, ' + this.name + '!');
};

function createStudent2(props) {
    return new Student3(props || {})
}

//这个createStudent()函数有几个巨大的优点：一是不需要new来调用，二是参数非常灵活，可以不传，也可以这么传：
var xiaolan = createStudent2({"name":"小兰"});
xiaolan.hello();

function PrimaryStudent(props){
    Student3.call(this,props||{});
}

function extend(child,parent){
    function F(){};
    F.prototype  = parent.prototype;
    child.prototype = new F();
    child.prototype.constructor = child;
}
extend(PrimaryStudent,Student3);

var xiaoxiao = new PrimaryStudent();
console.log(xiaoxiao);

xiaoxiao.hey();

console.log(xiaoxiao instanceof PrimaryStudent);
console.log(xiaoxiao instanceof Student3);
